﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.Serialization;
using System.Reflection;
namespace K.EnterpriseLibary
{
    [DataContract]
    [Serializable]
    public class BaseInfo
    {
        public BaseInfo()
        { 
        
        }

        public BaseInfo Self
        {
            get
            {
                return this;
            }
        }

        protected virtual string KeyMemeber
        {
            get
            {
                return null;
            }
        }

        public override int GetHashCode()
        {
            if (KeyMemeber == null)
            {
                return base.GetHashCode();
            }
            else
            {
                Type thisType = this.GetType();
                MemberInfo[] memberInfos = thisType.GetMember(KeyMemeber);
                if (memberInfos == null || memberInfos.Length == 0)
                    throw new Exception("Key member is not a field or property.");
                MemberInfo memberInfo = memberInfos[0];

                if (memberInfo is FieldInfo)
                {
                    FieldInfo fieldInfo = memberInfo.Cast<FieldInfo>();
                    object fieldValue = fieldInfo.GetValue(this);
                    if (fieldValue.IsNull())
                        return 0;
                    return fieldValue.GetHashCode();
                }
                else if (memberInfo is PropertyInfo)
                {
                    PropertyInfo propertyInfo = memberInfo.Cast<PropertyInfo>();
                    object propertyValue = propertyInfo.GetValue(this, null);
                    if (propertyValue.IsNull())
                        return 0;
                    return propertyValue.GetHashCode();
                }
                else
                {
                    throw new KException("Key member is not a field or property."
                        , "KeyMemeber", KeyMemeber);
                }
            }
        }



        public override bool Equals(object obj)
        {
            if (((object)this) == obj)
                return true;

            if (obj == null)
                return false;

            if (this.GetType() != obj.GetType())
                return false;

            if (KeyMemeber == null)
            {
                return false;
            }
            else
            {
                Type thisType = this.GetType();
                MemberInfo[] memberInfos = thisType.GetMember(KeyMemeber);
                if (memberInfos == null || memberInfos.Length == 0)
                    throw new KException("Key member is not a field or property."
                        , "KeyMemeber", KeyMemeber);
                 MemberInfo memberInfo = memberInfos[0];

                if (memberInfo is FieldInfo)
                {
                    FieldInfo fieldInfo = memberInfo.Cast<FieldInfo>();
                    return fieldInfo.GetValue(obj).Equals(fieldInfo.GetValue(this));
                }
                else if (memberInfo is PropertyInfo)
                {
                    PropertyInfo propertyInfo = memberInfo.Cast<PropertyInfo>();
                    object destKey = propertyInfo.GetValue(obj, null);
                    object sourceKey = propertyInfo.GetValue(this, null);
                    if (destKey == sourceKey)
                        return true;

                    if (destKey == null && sourceKey != null)
                        return false;

                    if (destKey != null && sourceKey == null)
                        return false;

                    return destKey.Equals(sourceKey);

                }
                else
                {
                    throw new KException("Key member is not a field or property."
                        , "KeyMemeber", KeyMemeber);
                }
            }
        }

        /// <summary>
        /// 二進制複製
        /// </summary>
        /// <param name="srcObject"></param>
        public void BinaryCopyFrom(BaseInfo srcObject)
        {
            srcObject.CheckNull("Source object cannot be null.");

            if (this.GetType() != srcObject.GetType())
                throw new KException("Object type is not matched."
                    , "SourceType", srcObject.GetType().FullName
                    , "DestType", this.GetType().FullName);

            FieldInfo[] fieldInfos = srcObject.GetType().GetFields(BindingFlags.NonPublic
                | BindingFlags.Public
                | BindingFlags.Instance
                | BindingFlags.GetField
                | BindingFlags.SetField);
            foreach (FieldInfo fieldInfo in fieldInfos)
            {
                fieldInfo.SetValue(this, fieldInfo.GetValue(srcObject).BinaryClone());
            }
        }
    }
}
